async function AmmoPhysics() {

	if ('Ammo' in window === false) {

		console.error('AmmoPhysics: Couldn\'t find Ammo.js');
		return;

	}

	const AmmoLib = await Ammo(); // eslint-disable-line no-undef

	const frameRate = 60;

	let meshes = []; //mass大于零的mesh
	let meshMap = new WeakMap(); //mesh body 键值对
	let margin = 0.05;
	
	//配置物理世界
	const collisionConfiguration = new AmmoLib.btDefaultCollisionConfiguration();
	const dispatcher = new AmmoLib.btCollisionDispatcher(collisionConfiguration);
	const broadphase = new AmmoLib.btDbvtBroadphase();
	const solver = new AmmoLib.btSequentialImpulseConstraintSolver();
	const world = new AmmoLib.btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
	world.setGravity(new AmmoLib.btVector3(0, -9.8, 0));

	const worldTransform = new AmmoLib.btTransform();

	//

	function getShape(mesh, shapeType) {

		let geometry = mesh.geometry;

		const parameters = geometry.parameters;
		// TODO change type to is*

		//人物胶囊
		if (shapeType === 'Capsule') {
			let shape = new Ammo.btCapsuleShape(0.5, 1);
			shape.setMargin(margin);
			return shape;
		}

		if (geometry.type === 'BufferGeometry') {

			//组合形状
			if (shapeType === 'Compound') {

				let compound = new Ammo.btCompoundShape();
				let children = mesh.children;

				for (let l = 0; l < children.length; l++) {
					
					if (children[l].name.indexOf('pengZhuang') > -1) {
						
						children[l].visible = false;
						
						let coords = children[l].geometry.attributes.position.array;
						let shape = new Ammo.btConvexHullShape();
						let tempBtVec3_1 = new Ammo.btVector3;
						let postion = children[l].position;
						postion = new Ammo.btVector3(postion.x, postion.y, postion.z);

						for (let i = 0, il = coords.length; i < il; i += 3) {
							tempBtVec3_1.setValue(coords[i], coords[i + 1], coords[i + 2]);
							const lastOne = (i >= (il - 3));
							shape.addPoint(tempBtVec3_1, lastOne);
						}
						
						let localTrans = new Ammo.btTransform();
						localTrans.setIdentity();
						localTrans.setOrigin(postion);

						compound.addChildShape(localTrans, shape);
					}
				}
				compound.setMargin(margin);
				return compound;
			}

			//动态物体 凸形类型
			if (shapeType === 'Convex') {

				let coords = geometry.attributes.position.array;
				let shape = new Ammo.btConvexHullShape();
				let tempBtVec3_1 = new Ammo.btVector3;

				for (let i = 0, il = coords.length; i < il; i += 3) {
					tempBtVec3_1.setValue(coords[i], coords[i + 1], coords[i + 2]);
					const lastOne = (i >= (il - 3));
					shape.addPoint(tempBtVec3_1, lastOne);
				}
				shape.setMargin(margin);
				return shape;
			}

			//动态物体 boxshape类型
			if (shapeType === 'Box') {

				let boundingBox = geometry.boundingBox;

				const sx = (boundingBox.max.x - boundingBox.min.x) / 2;
				const sy = (boundingBox.max.y - boundingBox.min.y) / 2;
				const sz = (boundingBox.max.z - boundingBox.min.z) / 2;

				const shape = new AmmoLib.btBoxShape(new AmmoLib.btVector3(sx, sy, sz));
				shape.setMargin(margin);

				return shape;
			}

			// 静态物体trianglemesh类型
			if (shapeType === 'Triangle') {
				let geo;

				if (geometry.index !== null) {
					geo = geometry.toNonIndexed();
				} else {
					geo = geometry;
				}
				const positionAttribute = geo.getAttribute('position');

				var mesh = new Ammo.btTriangleMesh(true, true);

				for (let i = 0; i < positionAttribute.count; i += 3) {
					mesh.addTriangle(
						new Ammo.btVector3(positionAttribute.getX(i), positionAttribute.getY(i),
							positionAttribute
							.getZ(i)),
						new Ammo.btVector3(positionAttribute.getX(i + 1), positionAttribute.getY(i + 1),
							positionAttribute.getZ(i + 1)),
						new Ammo.btVector3(positionAttribute.getX(i + 2), positionAttribute.getY(i + 2),
							positionAttribute.getZ(i + 2)),
						false
					);
				}
				var shape = new Ammo.btBvhTriangleMeshShape(mesh, true, true);
				shape.setMargin(margin);
				return shape;
			}

		}
		
		if (geometry.type === "ConeGeometry") {
		
			let coords = geometry.attributes.position.array;
			let shape = new Ammo.btConvexHullShape();
			let tempBtVec3_1 = new Ammo.btVector3;
			
			for (let i = 0, il = coords.length; i < il; i += 3) {
				tempBtVec3_1.setValue(coords[i], coords[i + 1], coords[i + 2]);
				const lastOne = (i >= (il - 3));
				shape.addPoint(tempBtVec3_1, lastOne);
			}
			shape.setMargin(margin);
			return shape;
		
		}
		
		if (geometry.type === 'BoxGeometry') {

			const sx = parameters.width !== undefined ? parameters.width / 2 : 0.5;
			const sy = parameters.height !== undefined ? parameters.height / 2 : 0.5;
			const sz = parameters.depth !== undefined ? parameters.depth / 2 : 0.5;

			const shape = new AmmoLib.btBoxShape(new AmmoLib.btVector3(sx, sy, sz));
			shape.setMargin(margin);

			return shape;

		} else if (geometry.type === 'SphereGeometry' || geometry.type === 'IcosahedronGeometry') {

			const radius = parameters.radius !== undefined ? parameters.radius : 1;

			const shape = new AmmoLib.btSphereShape(radius);
			shape.setMargin(margin);

			return shape;

		}

		return null;

	}

	function addMesh(mesh, mass = 0, shapeType = 'Convex') {

		if (mesh.userData.mass) mass = mesh.userData.mass;

		const shape = getShape(mesh, shapeType);

		if (shape !== null) {

			handleMesh(mesh, mass, shape);

		}

	}

	function handleMesh(mesh, mass, shape) {

		const position = mesh.position;
		const quaternion = mesh.quaternion;

		const transform = new AmmoLib.btTransform();
		transform.setIdentity();
		transform.setOrigin(new AmmoLib.btVector3(position.x, position.y, position.z));
		transform.setRotation(new AmmoLib.btQuaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w));

		const motionState = new AmmoLib.btDefaultMotionState(transform);

		const localInertia = new AmmoLib.btVector3(0, 0, 0);
		shape.calculateLocalInertia(mass, localInertia);

		const rbInfo = new AmmoLib.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia);

		const body = new AmmoLib.btRigidBody(rbInfo);

		if (mesh.userData.jueSeHao) {
			body.setSleepingThresholds(0.0, 0.0); //不休眠（一直是活动物体
			body.setAngularFactor(0); //0禁止旋转
		}
		
		if (mesh.userData.kuaiSuWuTi) {
			//快速物体开启连续检测
			body.setCcdMotionThreshold(0.5);//运动距离大于0.5开启
			body.setCcdSweptSphereRadius(0.01);
		}
		
		body.setFriction(4);//摩擦力

		world.addRigidBody(body);

		meshes.push(mesh);
		meshMap.set(mesh, body);

		// Disable deactivation
		body.setActivationState(4);
		
		// if (mass > 0) {
		// 	meshes.push(mesh);
		// 	meshMap.set(mesh, body);

		// 	// Disable deactivation
		// 	body.setActivationState(4);
		// }

		//物体破坏准备
		mesh.userData.physicsBody = body;
		mesh.userData.collided = false;
		const btVecUserData = new Ammo.btVector3(0, 0, 0);
		btVecUserData.threeObject = mesh;
		body.setUserPointer(btVecUserData);
	}

	function deleteMesh(mesh) {
		world.removeRigidBody(mesh.userData.physicsBody);
		meshes.forEach( (m, i, a) => {
			if (m == mesh) a.splice(i, 1)
		});
		meshMap.delete(mesh);
	}
	//

	function setMeshPosition(mesh, position, velocity, dongZuo) {

		if (mesh.isMesh) {

			const body = meshMap.get(mesh);
			worldTransform.setIdentity();

			if (mesh.userData.jueSeHao) {
				const motionState = body.getMotionState();
				motionState.getWorldTransform(worldTransform);
				
				if (!position) {

					let vy = body.getLinearVelocity().y();

					if (velocity) {
						//跳跃
						if (dongZuo == 'tiao') body.setLinearVelocity(new AmmoLib.btVector3(velocity.x, velocity.y,
							velocity.z));
						//左右移动
						else body.setLinearVelocity(new AmmoLib.btVector3(velocity.x, vy, velocity.z));
					}
					return;//节省时间

				}else {
					//设置角色位置
					worldTransform.setOrigin(new AmmoLib.btVector3(position.x, position.y, position.z));
				}
			} else {

				body.setAngularVelocity(new AmmoLib.btVector3(0, 0, 0));
				if (velocity) {
					body.setLinearVelocity(new AmmoLib.btVector3(velocity.x, velocity.y, velocity.z));
				}
				worldTransform.setOrigin(new AmmoLib.btVector3(position.x, position.y, position.z));
			}

			body.setWorldTransform(worldTransform);
		}

	}

	//内置step
	// let lastTime = 0;

	// function step() {

	// const time = performance.now();
	// if (lastTime > 0) {
	// 	const delta = (time - lastTime) / 1000;
	// 	// console.time( 'world.step' );
	// 	world.stepSimulation(delta, 10);
	// 	// console.timeEnd( 'world.step' );
	// }
	// lastTime = time;

	function step(deltaTime) {

		world.stepSimulation(deltaTime, 10);

		//更新物体状态

		for (let i = 0, l = meshes.length; i < l; i++) {

			const mesh = meshes[i];

			if (mesh.isMesh) {
				
				//快速物体检测用
				mesh.userData.shangCiWeiZhi = { x: mesh.position.x, y: mesh.position.y, z: mesh.position.z };
				
				const body = meshMap.get(mesh);

				const motionState = body.getMotionState();
				motionState.getWorldTransform(worldTransform);

				const position = worldTransform.getOrigin();
				
				const quaternion = worldTransform.getRotation();
				mesh.position.set(position.x(), position.y(), position.z());

				if (!mesh.userData.jueSeHao) mesh.quaternion.set(quaternion.x(), quaternion.y(), quaternion.z(), quaternion.w());

				//破坏检测用
				mesh.userData.collided = false;
				
			}

		}

	}

	// animate

	// setInterval(step, 1000 / frameRate);

	return {
		physicsDispatcher: dispatcher,
		physicsAddMesh: addMesh,
		physicsDeleteMesh: deleteMesh,
		physicsSetMeshPosition: setMeshPosition,
		physicsStep: step,
		physicsMeshes: meshes
	};

}

export default AmmoPhysics;
